package com.feng.oauth2;


import com.alibaba.druid.pool.DruidDataSource;
import com.feng.oauth2.oauth.domain.oauth.CustomJdbcClientDetailsService;
import com.feng.oauth2.oauth.domain.oauth.CustomJdbcTokenStore;
import com.feng.oauth2.oauth.infrastructure.OauthUserApprovalHandler;
import com.feng.oauth2.oauth.infrastructure.jdbc.SOSAuthorizationCodeServices;
import com.feng.oauth2.oauth.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
import org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.nio.charset.Charset;


/**
 * @author feng
 * @description TODO
 * @date 2019/1/10 16:31]]
 */
@Configuration
@EnableAuthorizationServer
public class MyOauthServer extends AuthorizationServerConfigurerAdapter {

    @Resource
    private DruidDataSource dataSource;
    @Autowired
    private CustomJdbcTokenStore tokenStore;
    @Autowired
    private SOSAuthorizationCodeServices sosAuthorizationCodeServices;
    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;
    @Autowired
    @Qualifier("ouathUserService")
    private UserService ouathUserService;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore);
        endpoints.authenticationManager(authenticationManager);
        endpoints.userDetailsService(ouathUserService);
        endpoints.tokenServices(getTokenServices());
        endpoints.authorizationCodeServices(sosAuthorizationCodeServices);
        //endpoints.userApprovalHandler(getTokenStoreUserApprovalHandler());

    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
       clients.jdbc(dataSource);
    }

    @Bean
    ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(){
        ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter = new ClientCredentialsTokenEndpointFilter();
        clientCredentialsTokenEndpointFilter.setAuthenticationManager(authenticationManager);
        clientCredentialsTokenEndpointFilter.setContinueChainBeforeSuccessfulAuthentication(false);
        clientCredentialsTokenEndpointFilter.setAuthenticationEntryPoint(oAuth2AuthenticationEntryPoint());
        return clientCredentialsTokenEndpointFilter;
    }


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
       security.allowFormAuthenticationForClients();
       security.authenticationEntryPoint(oAuth2AuthenticationEntryPoint());
       //这个是security升级后，密码加密做了优化，如果想和之前的兼容，这里使用NoOpasswordEncoder
       security.passwordEncoder(NoOpPasswordEncoder.getInstance());
       security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Bean
    DefaultTokenServices getTokenServices(){
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(getTokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setClientDetailsService(getCustomJdbcClientDetailsService());
        return defaultTokenServices;
    }
    @Bean
    CustomJdbcTokenStore getTokenStore(){
        return new CustomJdbcTokenStore(dataSource);
    }
    @Bean
    SOSAuthorizationCodeServices getJdbcAuthorizationCodeServices(){

        return new SOSAuthorizationCodeServices(dataSource);
    }

    @Bean
    DefaultOAuth2RequestFactory getDefaultOAuth2RequestFactory(){
        return new DefaultOAuth2RequestFactory(getCustomJdbcClientDetailsService());
    }

    @Bean
    OauthUserApprovalHandler getTokenStoreUserApprovalHandler(){
        OauthUserApprovalHandler tokenStoreUserApprovalHandler = new OauthUserApprovalHandler();
        tokenStoreUserApprovalHandler.setClientDetailsService(getCustomJdbcClientDetailsService());
        tokenStoreUserApprovalHandler.setTokenStore(getTokenStore());
        tokenStoreUserApprovalHandler.setRequestFactory(getDefaultOAuth2RequestFactory());
        return tokenStoreUserApprovalHandler;
    }

    @Bean
    CustomJdbcClientDetailsService getCustomJdbcClientDetailsService(){
        return new CustomJdbcClientDetailsService(dataSource);
    }
    @Bean
    ClientDetailsUserDetailsService clientDetailsUserDetailsService(){
        return new ClientDetailsUserDetailsService(getCustomJdbcClientDetailsService());
    }
    @Bean
    OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint() {
        final OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
//        entryPoint.setRealmName("oauth/client");
        entryPoint.setTypeName("Basic");
        return entryPoint;
    }


    public static void main(String[] args) throws Exception{
        String str = "customer\\product\\20171110120154628.jpg";
        System.out.println(str.replace("\\", "."));
        String ss = "http://timages.yitongquan.cn/shanbao/vip/cardPic/ 15351120170724184855643.jpg";
        System.out.println(URLEncoder.encode(ss, "utf-8"));
        System.out.println(org.apache.catalina.util.URLEncoder.DEFAULT.encode(ss, Charset.forName("utf-8") ));
    }
}
